﻿using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Tsual.Util;
using Tsual.Util.Redis;
using Tsual.Wechat.Cache;
using Tsual.Wechat.Message;
using Tsual.Wechat.Message.Exceptions;
using Tsual.Wechat.Message.Impl;
using Tsual.Wechat.Message.Impl.Internal;
using Tsual.Wechat.Message.Impl.Response;
using Tsual.Wechat.Message.Interface.Request;
using Tsual.Wechat.Message.Interface.Response;
using System.Web;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Mvc;
using System.Xml.Linq;
using System.Net;
using System.Collections;
using Tsual.Wechat;
using Tsual.Wechat.Formatters;
using Microsoft.AspNetCore.Hosting;
using Tsual.Wechat.Enums;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Tsual.Wechat.Filters;
using System.Reflection;
using Tsual.Wechat.Controllers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Options;

namespace Tsual.Wechat.Message
{
    public enum WechatReponseMsgTypes
    {
        text = 1,
        image,
        voice,
        video,
        music,
        news
    }

    public enum WechatRequestMsgTypes
    {
        text = 1,
        image,
        voice,
        voice_recognition,
        video,
        shortvideo,
        location,
        link,
        @event
    }

    /// <summary>
    /// 微信消息处理器执行优先级
    /// </summary>
    public enum WechatMessageHandlerPrivilege
    {
        VeryLow = 1,
        Low,
        Nomarl,
        Higth,
        VeryHigh,
        Master,
    }

    /// <summary>
    /// 标记微信消息处理器执行优先级，级别越高排序越前
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class HandlerPrivilegeAttribute : Attribute
    {
        public HandlerPrivilegeAttribute(WechatMessageHandlerPrivilege level)
        {
            Privilege = level;
        }

        internal WechatMessageHandlerPrivilege Privilege { get; set; }
    }

    /// <summary>
    /// 微信消息处理器，实现接口就能处理消息，用HandlerPrivilegeAttribute标记执行优先级
    /// </summary>
    /// <typeparam name="TMessage">处理器的类型</typeparam>
    public interface IWechatMessageHandler<TMessage> where TMessage : IWechatHandlableMessageRequest
    {
        bool CanHandle(TMessage RequestMessageModel);
        WechatMessageHandleResult Handle(TMessage RequestMessageModel);
    }



    public class WechatMessageHandleResult
    {
        public bool Success { get; private set; }
        public IWechatMessageHandleResult Result { get; private set; }

        private WechatMessageHandleResult() { }

        public static WechatMessageHandleResult Sucess(IWechatMessageHandleResult Result) => new WechatMessageHandleResult() { Success = true, Result = Result };
        public static WechatMessageHandleResult Error(IWechatMessageHandleResult Result) => new WechatMessageHandleResult() { Success = false, Result = Result };
    }

    public class WechatMessageMaster
    {
        internal WechatMessageMaster() { }

        private Dictionary<Type, List<Type>> RootMap;
        private readonly ReaderWriterLockSlim RootMapSlim = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

        private IWechatResponseText CreateNoHandlerReturn(IWechatRequestMessage request) => new WechatResponseText()
        {
            Content = WechatContext.Instance.ResponseTextNotfound,
            FromUserName = request.ToUserName,
            ToUserName = request.FromUserName,
            CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds())
        };

        private IWechatResponseText CreateErrorReturn(IWechatRequestMessage request) => new WechatResponseText()
        {
            Content = WechatContext.Instance.ResponseTextError,
            FromUserName = request.ToUserName,
            ToUserName = request.FromUserName,
            CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds())
        };

        private IWechatResponseText CreateTimeoutReturn(IWechatRequestMessage request) => new WechatResponseTimeoutText()
        {
            Content = WechatContext.Instance.ResponseTextTimeout,
            FromUserName = request.ToUserName,
            ToUserName = request.FromUserName,
            CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds())
        };



        private IWechatResponseText CreateWechatServerErrorReturn(IWechatRequestMessage request) => new WechatResponseText()
        {
            Content = "未知消息类型:" + (request as IWechatHandlableMessageRequest)?.MessagesType,
            FromUserName = request.ToUserName,
            ToUserName = request.FromUserName,
            CreateTime = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds())
        };

        private static Dictionary<WechatRequestMsgTypes, Type> RequestTypeMapping = new Dictionary<WechatRequestMsgTypes, Type>()
        {
            {WechatRequestMsgTypes.image,typeof(IWechatRequestImage) },
            {WechatRequestMsgTypes.link,typeof(IWechatRequestLink) },
            {WechatRequestMsgTypes.location,typeof(IWechatRequestLocation) },
            {WechatRequestMsgTypes.shortvideo,typeof(IWechatRequestShortVideo) },
            {WechatRequestMsgTypes.text,typeof(IWechatRequestText) },
            {WechatRequestMsgTypes.video,typeof(IWechatRequestVideo) },
            {WechatRequestMsgTypes.voice,typeof(IWechatRequestVoice) },
            {WechatRequestMsgTypes.voice_recognition,typeof(IWechatRequestRecognitionVoice) },
            {WechatRequestMsgTypes.@event,typeof(IWechatRequestEvent) },
        };

        private async Task printRootMapAsync(ILogger logger) => await Task.Run(() =>
        {
            RootMapSlim.EnterReadLock();
            StringBuilder sb = new StringBuilder();
            foreach (var t in RootMap)
            {
                sb.AppendLine($"{t.Key.FullName}:");
                foreach (var t0 in t.Value)
                    sb.AppendLine($"    {t0.FullName} :Privilege=>{(t0.GetCustomAttributes(typeof(HandlerPrivilegeAttribute), true).FirstOrDefault() as HandlerPrivilegeAttribute)?.Privilege ?? WechatMessageHandlerPrivilege.Nomarl}");
            }
            RootMapSlim.ExitReadLock();
            logger.LogDebug("最终注册的微信消息处理器：\n   {0}", sb.ToString());
        });

        public async Task SearchAssemblyAndRegistHandlersAsync(ILogger logger)
            => await Task.Run(() =>
            {
                RootMapSlim.EnterWriteLock();
                RootMap = new Dictionary<Type, List<Type>>();

                AppDomain.CurrentDomain.GetAssemblies()
                    .AsParallel()
                    .SelectMany(ass => ass.GetTypes()
                            .Where(ast => ast.GetInterfaces().Count() > 0)
                            .Where(ast => ast.GetInterfaces().Where(t => t.IsGenericType).Where(t => t.GenericTypeArguments.Where(ag => typeof(IWechatHandlableMessageRequest).IsAssignableFrom(ag)).Count() == 1).Count() == 1)
                            .Select(ast => new KeyValuePair<Type, Type>(ast, ast.GetInterfaces().Where(t => t.IsGenericType).SelectMany(t => t.GenericTypeArguments.Where(ag => typeof(IWechatHandlableMessageRequest).IsAssignableFrom(ag))).First())))
                    .ForAll(t =>
                    {
                        if (!RootMap.ContainsKey(t.Value)) RootMap.Add(t.Value, new List<Type>());
                        RootMap[t.Value].Add(t.Key);
                        logger?.LogTrace("注册了微信消息处理器{0}", t.Key.FullName);
                    });
                RootMapSlim.ExitWriteLock();
#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
                printRootMapAsync(logger);
#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
            });

        private object CreateDIObject(Type type, IServiceProvider serviceProvider) =>
            type.GetConstructors().ToList()
                .Select(ctor =>
                {
                    try
                    {
                        var param = ctor.GetParameters()
                            .Select(t => serviceProvider.GetService(t.ParameterType))
                            .ToArray();
                        return ctor.Invoke(param);
                    }
                    catch (Exception)
                    {
                        return null;
                    }
                })
                .Where(t => t != null)
                .FirstOrDefault();

        private IWechatMessageHandleResult HandleMessageAsyncInner<TMessage>(TMessage message, IServiceProvider serviceProvider, ILogger logger = null) where TMessage : IWechatRequestMessage
        {
            logger?.LogTrace("开始处理微信消息msgid:" + message.MsgId);
            WechatRequestMsgTypes typeEnum;
            if (!Enum.TryParse((message as IWechatMessageRequestModel).MsgType, out typeEnum))
            {
                logger?.LogError("未知微信消息类型:" + (message as IWechatMessageRequestModel)?.MsgType);
                return CreateWechatServerErrorReturn(message);
            }

            RootMapSlim.EnterReadLock();

            if (!RootMap.ContainsKey(RequestTypeMapping[typeEnum]))
            {
                logger?.LogDebug("没有找到对应的消息Handler:" + (message as IWechatMessageRequestModel)?.MsgType);
                return CreateNoHandlerReturn(message);
            }

            var msgHandler = RootMap[RequestTypeMapping[typeEnum]].ToList()
                .OrderByDescending(t => (t.GetCustomAttributes(typeof(HandlerPrivilegeAttribute), true).FirstOrDefault() as HandlerPrivilegeAttribute)?.Privilege ?? WechatMessageHandlerPrivilege.Nomarl)
                .Select(type => new KeyValuePair<Type, object>(type, CreateDIObject(type, serviceProvider)))
                .Where(t => t.Value != null)
                .Where(t => (bool)t.Key.GetMethod("CanHandle").Invoke(t.Value, new object[] { message }))
                .FirstOrDefault();

            RootMapSlim.ExitReadLock();

            if (msgHandler.Value == null)
            {
                logger?.LogDebug("没有找到对应的消息Handler:" + (message as IWechatMessageRequestModel)?.MsgType);
                return CreateNoHandlerReturn(message);
            }
            else
            {
                WechatMessageHandleResult handleResult = null;
                try
                {
                    var task = new Task<WechatMessageHandleResult>(() => msgHandler.Key.GetMethod("Handle").Invoke(msgHandler.Value, new object[] { message }) as WechatMessageHandleResult);
                    var time_remain = Convert.ToInt32(Convert.ToInt64(message.CreateTime + 4) * 1000 - DateTimeOffset.Now.ToUnixTimeMilliseconds());
                    if (time_remain < 0)
                    {
                        logger?.LogError("微信消息开始前就已超时，仍然处理，但不返回");
                        task.Start();
                    }
                    else
                    {
                        task.Start();
                        task.Wait(time_remain);

                        switch (task.Status)
                        {
                            case TaskStatus.RanToCompletion:
                                return task.Result?.Result;
                            case TaskStatus.Running:
                            case TaskStatus.WaitingForActivation:
                            case TaskStatus.WaitingForChildrenToComplete:
                            case TaskStatus.WaitingToRun:
                                return CreateTimeoutReturn(message);
                            case TaskStatus.Faulted:
                                throw task.Exception;
                            default:
                                return CreateErrorReturn(message);
                        }
                    }


                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "消息Handler未能成功处理消息");
                    return CreateErrorReturn(message);
                }
                if (handleResult == null || !handleResult.Success)
                {
                    logger.LogError("消息Handler未能成功处理消息");
                    return CreateErrorReturn(message);
                }
                return handleResult.Result;
            }
        }

        public async Task<IWechatMessageHandleResult> HandleMessageAsync<TMessage>(TMessage message, IServiceProvider serviceProvider, ILogger logger = null) where TMessage : IWechatRequestMessage
        {
            RedLockFactory redLockFactory = serviceProvider.GetService<RedLockFactory>();
            var lock_key = WechatCacheKeyEnum.USER_OPERATION_LOCK.ToRedisKey() + "_" + message.FromUserName;
            using (var redLock = await redLockFactory.CreateLockAsync(lock_key, TimeSpan.FromSeconds(4)))
            {
                return redLock.IsAcquired ? HandleMessageAsyncInner(message, serviceProvider, logger) : CreateTimeoutReturn(message);
            }

        }
    }
}